package com.likui.boot.web;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.MediaType;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.likui.boot.common.OperationResult;
import com.likui.boot.common.repository.DataSourceRequest;
import com.likui.boot.common.repository.Filter;
import com.likui.boot.common.repository.Filters;
import com.likui.boot.common.repository.SearchFilter.Operator;
import com.likui.boot.model.User;
import com.likui.boot.service.UserService;
import com.likui.boot.util.ReflectionUtils;
import com.likui.boot.util.SpecificationUtil;

@RestController
@RequestMapping("/react")
public class WebPackController {

	@Autowired
	private UserService userService;

	@ModelAttribute
	protected void prepareModel(HttpServletRequest request, HttpServletResponse response, Model model,
			@RequestParam(value = "id", defaultValue = "_empty", required = false) String id,
			@RequestParam(value = "uuid", defaultValue = "_empty", required = false) String uuid) {

		response.setHeader("Access-Control-Allow-Origin", "Accept");
		response.setHeader("Access-Control-Allow-Credentials", "Accept");
		response.setHeader("Access-Control-Expose-Headers", "Accept");
		response.setHeader("Vary", "Accept");

		if (!id.equals("_empty") || !uuid.equals("_empty")) {
			model.addAttribute("entity", userService.findOne(!id.equals("_empty") ? id : uuid));
		}
	}

	@RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult login(HttpServletRequest request,
			@RequestParam(value = "username", required = false) String userName,
			@RequestParam(value = "password", required = false) String password) {
		return OperationResult.buildSuccessResult(new User());
	}

	@RequestMapping(value = "/checkLogin", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult checkLogin(HttpServletRequest request) {
		return OperationResult.buildSuccessResult(new User());
	}

	@RequestMapping(value = "/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult index(HttpServletRequest request, @RequestParam(value = "_page", required = false) int page,
			@RequestParam(value = "_limit", required = false) int limit) {
		Page<User> pageUser = userService.findAll(new PageRequest(page - 1, limit));
		return OperationResult.buildSuccessResult(pageUser);
	}

	@RequestMapping(value = "/users", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult saveUser(HttpServletRequest request, @Valid @RequestBody User user,
			BindingResult bindingResult) throws Exception {
		if (this.hasError(user, bindingResult)) {
			return OperationResult.buildFailureResult(this.getErrorMessage(user, bindingResult));
		}
		userService.save(user);
		return OperationResult.buildSuccessResult();
	}

	@RequestMapping(value = "/users/remove", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult removeUser(HttpServletRequest request, @ModelAttribute("entity") User user) {
		userService.delete(user.getId());
		return OperationResult.buildSuccessResult();
	}

	@RequestMapping(value = "/users/patch", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult patchUser(HttpServletRequest request, @Valid @ModelAttribute("entity") User user,
			BindingResult bindingResult) throws Exception {
		if (this.hasError(user, bindingResult)) {
			return OperationResult.buildFailureResult(this.getErrorMessage(user, bindingResult));
		}
		userService.save(user);
		return OperationResult.buildSuccessResult();
	}

	@RequestMapping(value = "/users/query", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult query(HttpServletRequest request, @RequestParam(value = "_page", required = false) int page,
			@RequestParam(value = "_limit", required = false) int limit, @RequestBody Map<String, String> param) {

		Filter filter = new Filter();
		List<Filters> fs = new ArrayList<Filters>();
		for (String key : param.keySet()) {
			if (!StringUtils.isEmpty(param.get(key))) {
				Filters f = new Filters(key, Operator.LIKE, param.get(key));
				fs.add(f);
			}
		}
		filter.setFilters(fs);
		DataSourceRequest dsr = new DataSourceRequest();
		dsr.setFilter(filter);
		Specification<User> specification = SpecificationUtil.buildSpecification(dsr);

		Page<User> pageUser = userService.findAll(specification, new PageRequest(page - 1, limit));
		return OperationResult.buildSuccessResult(pageUser);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@RequestMapping(value = "/getDict", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
	public OperationResult getDict(HttpServletRequest request,
			@RequestParam(value = "type", required = false, defaultValue = "key") String type) {
		List list = new ArrayList();
		for (int i = 0; i < 3; i++) {
			Map dict = new HashMap();
			dict.put("key", "key" + i);
			dict.put("value", "value" + i);
			list.add(dict);
		}

		return OperationResult.buildSuccessResult(list);
	}

	private boolean hasError(User m, BindingResult result) {
		Assert.notNull(m);
		return result.hasErrors();
	}

	private String getErrorMessage(User m, BindingResult bindingResult) throws Exception {
		Assert.notNull(m);
		FieldError fieldError = bindingResult.getFieldError();
		String defaultMsg = fieldError.getDefaultMessage();

		String message = ReflectionUtils.getMetaDataValue(m, fieldError.getField()) + " :" + defaultMsg;
		return message;
	}
}
